<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 直接使用ES6提供的flat方法实现扁平化。
        // falt()方法会按照指定的深度递归遍历数组，arr.flat([depth])，
        // 参数depth不填时默认值为1，depth为Infinity表示展开任意深度的嵌套数组

        // 方式1：Es6的flat()方法

        let arr = [1, 2, 3, [3, 2, 8],[6, 3, 8]]

        function fn1() {
            return arr.flat(Infinity)
        }


        // 方式2：使用基础的递归遍历
        // 声明一个函数，遍历数组的每个元素，
        // 判断当前元素是否仍是数组，是的话递归执行这个函数，
        // 并把执行结果与当前结果数组合并，不是数组则直接将当前元素push到结果数组中。

        // let arr = [1,2,3,[3,2,8],[6,3,8]]
        function fn2(arr) {
            let result = [];
            for (let i = 0; i < arr.length; i++) {
                if (Array.isArray(arr[i])) {
                    result = result.concat(fn2(arr[i]));
                } else {
                    result.push(arr[i]);
                }
            }
            return result;
        }


        // 方式3：使用reduce函数递归遍历
        // 与第二种方法思路是一样的，区别在于这里利用reduce函数的特性遍历数组并保存每一次的计算结果。

        // let arr = [1,2,3,[3,2,8],[6,3,8]]
        function fn3(arr) {
            return arr.reduce((pre, current) => {
                if (Array.isArray(current)) {
                    return pre.concat(fn3(current));
                } else {
                    return pre.concat(current);
                }
            }, []);
        }

        // 方式4：数组强制类型转换
        // 对于数组对象，toString方法连接数组并返回一个字符串，其中包含用逗号分隔的每个数组元素。
        // 返回的字符串使用split分割成子字符串数组，最后将数组中每个元素的类型转换为Number型。

        //  let arr = [1,2,3,[3,2,8],[6,3,8]]
        function fn4(arr) {
            return arr.toString().split(',').map((item) => Number(item));
        }

        //  方式5：while循环结合findIndex与concat
        // 在while循环中，使用findIndex判断当前数组是否是一个多维
        // 数组（即判断数组是否存在Array类型的元素），如是，
        // 则使用…扩展操作符展开作为concat方法的参数进行合并，
        // 并赋值给当前数组，再执行下一次循环的条件判断，直至得到一个一维数组。

        function fn5(arr) {
            while (arr.findIndex((item) => Array.isArray(item)) > 0) {
                arr = [].concat(...arr);
            }
            return arr;
        }

        // 方式6：使用JSON的函数和正则表达式
        // 使用JSON的序列化函数stringify()先对数组进行序列化
        // 再用正则去掉[],得到的结果在最外层加上[]后使用JSON.parse()恢复成数组对象。

        function fn6(arr) {
            let result = JSON.stringify(arr).replace(/(\[|\])/g, '');
            result = '[' + result + ']';
            return JSON.parse(result);
        }

        // 方式7：使用堆栈stack
        // 创建一个栈结构和一个存放结果的空数组，然后遍历栈结构，
        // 判断元素如果是数组就使用扩展操作符展开再次入栈，不是就添加到结果数组的开头。

        function fn7(arr) {
            const stack = [...arr];
            const res = [];
            while (stack.length) {
                const next = stack.pop();
                if (Array.isArray(next)) {
                    stack.push(...next);
                } else {
                    res.unshift(next);
                }
            }
            return res
        }

        // 方式8：使用Generator 函数与递归结合
        // Generator 函数是 ES6 提供的一种异步编程解决方案，
        // 语法行为与传统函数完全不同。思路还是遍历当前数组，
        // 判断数组元素是否是数组，是则使用 yield 语句递归执行这个 Generator 函数，
        // 不是则使用 yield 表达式返回当前值。

        // let arr = [1,2,3,[3,2,8],[6,3,8]]
        function* fn8(arr) {
            for (const item of arr) {
                if (Array.isArray(item)) {
                    yield* fn8(item);
                } else {
                    yield item;
                }
            }
        }
        const array = [1,2,3,[3,2,8],[6,3,8]]
        
        const flattened = [...fn8(array)];





        console.log(fn1(arr));
        console.log(fn2(arr));
        console.log(fn3(arr));
        console.log(fn4(arr));
        console.log(fn5(arr));
        console.log(fn6(arr));
        console.log(fn7(arr));
        console.log(fn8(arr));
    </script>
</body>

</html>